/*
 * This file is part of algowala.
 *
 * algowala is copyright (c) 2012 Jagannathan Sampath <algowala@jagernot.com>
 *
 * algowala is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * algowala is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with algowala.  If not, see <http://www.gnu.org/licenses/>.
 *
*/
#include <iostream>
#include <sstream>
#include <cmath>

using namespace std;

#include "font.h"
#include "ansi_color_codes.h"

font::font (const string& filename) : modified (0) {

  xsize = 2;
  ysize = 2;
  charspc = 2 * xsize;
  headroom = 2 * ysize;
  fname = filename;
  load (fname);

}

font::~font () {
  if (modified) save ();
}

void font::load (const string& fn) {
  fname = fn;
  ifstream file (fname.c_str(), ios::in);
  if (!file) {
    cout << FAIL << "bad font file: " << fn << ENDL;
    return;
  } else {
    cout << LOAD << "<<< loading font from: " << fn;
    load (file); cout << ", done. >>>" << ENDL;
  }
}

void font::load (ifstream& file) {

  string ignore;

  characters.clear ();
  kern.clear ();

  file >> ignore >> name;
  file >> ignore >> nchars;

  int sum_char_width, sum_char_height;
  max_char_width = max_char_height = sum_char_width = sum_char_height = 0;
  
  for (int i = 0; i < nchars; i++) {
      char c; file >> c;
      glyph g;
      int nln; file >> nln;
      for (int l = 0; l < nln; ++l) {
        line ln;
        int npts; file >> npts;
        for (int s = 0; s < npts; ++s) {
          float x, y; file >> x >> y;
          ln.points.push_back (point<int>(x * xsize, y * ysize));
        }
        g.lines.push_back (ln);
      }
      
      g.find_width_height ();
      if (g.width > max_char_width) max_char_width = g.width;
      if (g.height > max_char_height) max_char_height = g.height;
      sum_char_width += g.width;
      sum_char_height += g.height;
      
      characters[c] = g;
  
  }
  
  avg_char_width = sum_char_width / nchars;
  avg_char_height = sum_char_height / nchars;
   
  lift = 2 * ysize;
  
  wordspc = 2 * charspc;
  
  int nkerns = 0;
  file >> ignore >> nkerns;
  for (int i = 0; i < nkerns; ++i) {
    char a, b;
    int k;
    file >> a >> b >> k;
    kern [a][b] = k * xsize;
  }
    
}

void font::save () {

  ofstream file (fname.c_str(), ios::out);
  if (!file) {
    cout << "cannot save font in: " << fname << endl;
    return;
  } else {
    cout << "saving font in: " << fname << endl;
  }

  stringstream ss1;
  int nc = 0;
  for (map<char, glyph>::iterator i = characters.begin(), j = characters.end(); i != j; ++i) {
    glyph& g = (*i).second;
    vector<line>& lines = g.lines;
    int nlines = lines.size ();
    if (nlines) {
      ss1 << (*i).first << ' ';
      ss1 << nlines << ' ';
      for (int s = 0; s < nlines; ++s) {
        vector < point<int> >& points = lines[s].points;
        int npts = points.size ();
        ss1 << npts << ' ';
        for (int m = 0; m < npts; ++m) {
          point<int>& pt = points[m];
          ss1 << (int)(pt.x / xsize) << ' ' << (int)(pt.y / ysize) << ' ';
        }
      }
      ss1 << endl;
      ++nc;
    }
  }

  file << "name " << name << endl;
  file << "num_chars " << nc << endl;

  file << ss1.str();

  stringstream ss2;
  int nk = 0;
  for (map<char, map<char, int> >::iterator i = kern.begin(), j = kern.end(); i != j; ++i) {
    char a = (*i).first;
    map<char, int>& m = (*i).second;
    for (map<char, int>::iterator p = m.begin(), q = m.end(); p != q; ++p) {
      char b = (*p).first;
      int k = (*p).second;
      if (k != 0) {
        ss2 << a << ' ' << b << ' ' << k/xsize << '\n';
        ++nk;
      }
    }
  }

  file << "num_kerns " << nk << endl;
  file << ss2.str();

}

int font::char_width (char c) { return characters[c].width;}
int font::char_height (char c) { return characters[c].height;}

void font::draw_char (char c, int x, int y, int z) {

  const glyph& gl = characters[c];
  const vector<line>& lines = gl.lines;

  for (unsigned int i = 0, nlines = lines.size(); i < nlines; ++i) {
    const line& li = lines[i];
    const vector< point<int> >& points = li.points;
    unsigned int npts = points.size();
    glBegin (GL_LINE_STRIP);
      for (unsigned int j = 0; j < npts; ++j) {
        const point<int>& p = points[j];
        glVertex3i(x + p.x, y + p.y, z);
      }
    glEnd ();
  }
}

const map<char, glyph>& font::get_chars () {
  return characters;
}

void font::set_chars (const map<char, glyph>& chars) {
  characters = chars;
  modified = 1;
}

int draw_string (const string& s, int x, int y, int z) {
  char prevc = ' ';
  for (int p = 0, q = s.length(); p < q; ++p) {
      char c = s[p];
      if (c == ' ') x += fnt.wordspc; else {
        x += fnt.kern[prevc][c];
        fnt.draw_char (c, x, y, z);
        x += (fnt.char_width (c) + fnt.charspc);
      }
      prevc = c;
  }
  return x;
}

int get_char_width (const string& s) {
	
  char prevc = ' ';
  int x = 0;
  for (int p = 0, q = s.length(); p < q; ++p) {
      char c = s[p];
      if (c == ' ') x += fnt.wordspc; else {
        x += (fnt.kern[prevc][c] + fnt.char_width (c) + fnt.charspc);
      }
      prevc = c;
  }
  
  return x;
}

int get_max_char_height (const string& s) {
  int h = 0;
  for (int p = 0, q = s.length(); p < q; ++p) {
		char c = s[p];
		int ch = fnt.char_height (c);
		if (ch > h) h = ch;
  }
  return h;
}
